//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.link.auth.core.config;

import com.link.auth.base.user.service.UserServiceDetail;
import com.link.auth.core.service.MyDefaultTokenServices;
import com.link.auth.core.service.MyRedisTokenStore;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.util.StringUtils;
import redis.clients.jedis.JedisPoolConfig;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    @Resource
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

    @Resource
    private UserServiceDetail userServiceDetail;

    @Resource
    private Environment env;

    @Resource
    private DataSource dataSource;

    @Bean
    public ClientDetailsService clientDetails() {
        return new JdbcClientDetailsService(dataSource);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        //设置token相关信息
        endpoints
                .tokenServices(myDefaultTokenServices())
                .authenticationManager(authenticationManager)
                //没有的话，刷新token会报错
                .userDetailsService(userServiceDetail);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //配置客户端信息
        clients.withClientDetails(clientDetails());
    }

    @Bean
    public TokenStore tokenStore() {
        return new MyRedisTokenStore(RedisConnectionFactory());
    }

    @Bean
    @Primary
    public MyDefaultTokenServices myDefaultTokenServices() {
        MyDefaultTokenServices resourceServerTokenServices = new MyDefaultTokenServices();
        resourceServerTokenServices.setTokenStore(tokenStore());
        resourceServerTokenServices.setSupportRefreshToken(true); //支持刷新token
        resourceServerTokenServices.setClientDetailsService(clientDetails());
        return resourceServerTokenServices;
    }

    /**
     * Redis配置
     *
     * @return
     */
    @Bean
    public RedisConnectionFactory RedisConnectionFactory() {
        JedisConnectionFactory jedisConnectionFactory;
        //判断redis是集群还是单机模式
        boolean clusterState = isCluster();
        if (clusterState) {
            //获取redis集群里的redis路径集合
            final String redisClusterUrlsKey = "spring.redis.cluster.nodes";
            String redisClusterUrlsRaw = env.getProperty(redisClusterUrlsKey);
            if (StringUtils.isEmpty(redisClusterUrlsRaw)) {
                throw new NullPointerException("yml key:" + redisClusterUrlsKey + "is null");
            }

            List<String> redisClusterUrls = env.getProperty(redisClusterUrlsKey, ArrayList.class);
            Set cluster = new HashSet(redisClusterUrls);
            //String masterName = env.getProperty("spring.redis.cluster-model.master-name");
            //RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration(masterName, sentinels);
            RedisClusterConfiguration  clusterConfiguration = new RedisClusterConfiguration(cluster);
            jedisConnectionFactory = new JedisConnectionFactory(clusterConfiguration);
            jedisConnectionFactory.setPassword(env.getProperty("spring.redis.cluster.password"));
        } else {
            jedisConnectionFactory = new JedisConnectionFactory();
            jedisConnectionFactory.setHostName(env.getProperty("spring.redis.host"));
            jedisConnectionFactory.setPort(Integer.parseInt(env.getProperty("spring.redis.port")));
            String redisPassword = env.getProperty("spring.redis.password");
            if (!StringUtils.isEmpty(redisPassword) && !"null".equals(redisPassword)) {
                jedisConnectionFactory.setPassword(redisPassword);
            }
        }
        jedisConnectionFactory.setTimeout(Integer.parseInt(env.getProperty("spring.redis.timeout")));
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(Integer.parseInt(env.getProperty("spring.redis.pool.max-idle")));
        jedisPoolConfig.setMaxTotal(Integer.parseInt(env.getProperty("spring.redis.pool.max-active")));
        jedisPoolConfig.setMaxWaitMillis(Integer.parseInt(env.getProperty("spring.redis.pool.max-wait")));
        jedisConnectionFactory.setDatabase(15);
        jedisConnectionFactory.setPoolConfig(jedisPoolConfig);

        return jedisConnectionFactory;
    }

    /**
     * 判断redis是否为集群模式
     * @author 何启谦
     * @return
     */
    private boolean isCluster() {
        //获取redis集群开关的状态
        final String redisClusterDtateKey = "spring.redis.cluster.state";
        String redisClusterStateRaw = env.getProperty(redisClusterDtateKey);
        if (StringUtils.isEmpty(redisClusterStateRaw)) {
            return false;
        }
        return Boolean.parseBoolean(redisClusterStateRaw);
    }
}
